<template>
    <div class="test-command">
        {{commander.state}}
        <div class="toolbar">
            <el-button-group>
                <el-button @click="commander.commands.redo()" :disabled="!commander.isEnable.value.redo">redo</el-button>
                <el-button @click="commander.commands.undo()" :disabled="!commander.isEnable.value.undo">undo</el-button>
            </el-button-group>

            &nbsp;

            <el-button-group>
                <el-button @click="commander.commands.larger()" :disabled="!commander.isEnable.value.larger">larger</el-button>
                <el-button @click="commander.commands.smaller()" :disabled="!commander.isEnable.value.smaller">smaller</el-button>
            </el-button-group>

        </div>
        <div class="panel">
            <div class="drag" :style="styles" @mousedown="drag.onmousedown"></div>
        </div>
    </div>
</template>

<script lang="ts">
    import {computed, createComponent, reactive} from "@vue/composition-api";
    import {suffixSize} from "@/utils/utils";
    import {Command, useCommander} from "@/plugins/Command";

    export default createComponent({
        name: 'test-command',
        setup() {

            /**
             * 将 commander 放进reactive里面之后，isEnable的计算属性本来是RefImpl变成了值对象，也就是说
             * 原来是 commander.isEnable.value，现在变成了 commander.isEnable
             * 为了确保统一性，将commander不放进 reactive里面了
             * @author  韦胜健
             * @date    2020/4/30 14:46
             */
            const commander = useCommander({})

            const state = reactive({
                top: 16,
                left: 16,
                scale: 1,
            })

            const styles = computed(() => ({
                top: suffixSize(state.top),
                left: suffixSize(state.left),
                transform: `scale(${state.scale})`
            }))

            const drag = {

                left: 0,
                top: 0,

                startX: 0,
                startY: 0,

                startLeft: 0,
                startTop: 0,

                draging: false,

                onmousedown: (e: MouseEvent) => {
                    drag.startX = e.clientX
                    drag.startY = e.clientY
                    drag.startLeft = state.left
                    drag.startTop = state.top

                    drag.draging = true

                    window.addEventListener('mousemove', drag.onmousemove)
                    window.addEventListener('mouseup', drag.onmouseup)
                },
                onmousemove: (e: MouseEvent) => {
                    const durX = e.clientX - drag.startX
                    const durY = e.clientY - drag.startY
                    state.left = drag.startLeft + durX
                    state.top = drag.startTop + durY
                },
                onmouseup: (e: MouseEvent) => {
                    const durX = e.clientX - drag.startX
                    const durY = e.clientY - drag.startY

                    drag.left = drag.startLeft + durX
                    drag.top = drag.startTop + durY

                    commander.commands.update()

                    drag.draging = false
                    window.removeEventListener('mousemove', drag.onmousemove)
                    window.removeEventListener('mouseup', drag.onmouseup)
                },
            }

            commander.register(new Command({
                name: 'update',
                execute() {
                    let {left, top, startLeft, startTop} = drag
                    return {
                        redo: () => {
                            state.left = left
                            state.top = top
                        },
                        undo: () => {
                            state.left = startLeft
                            state.top = startTop
                        },
                    }
                },
            }))
            commander.register(new Command({
                name: 'larger',
                execute() {
                    const {scale} = state
                    return {
                        redo: () => {
                            state.scale = scale + 0.1
                        },
                        undo: () => {
                            state.scale = scale
                        },
                    }
                },
                isEnable: () => {
                    return state.scale < 1.5
                }
            }))
            commander.register(new Command({
                name: 'smaller',
                execute() {
                    const {scale} = state
                    return {
                        redo: () => {
                            state.scale = scale - 0.1
                        },
                        undo: () => {
                            state.scale = scale
                        },
                    }
                },
                isEnable: () => {
                    return state.scale > 0.5
                }
            }))

            return {
                styles,
                drag,
                state,
                commander,
                count: 0,
            }
        },
    })
</script>

<style lang="scss">
    html, body {
        padding: 0;
        margin: 0;
    }

    .test-command {
        display: flex;
        flex-direction: column;
        height: 100vh;
        overflow: hidden;
        box-sizing: border-box;

        .toolbar {
            padding: 16px;
            box-sizing: border-box;
        }

        .panel {
            flex: 1;
            background-color: #f6f6f6;
            position: relative;

            .drag {
                position: absolute;
                width: 100px;
                height: 100px;
                background-color: #ddd;
                border-radius: 4px;
                cursor: pointer;

                &:hover {
                    background-color: #ccc;
                }
            }
        }
    }
</style>